CreateFile
ReadFile
WriteFile
CloseHandle
The functions ReadFile and WriteFile do not have A and W versions because the data can be any kind of binary data. However, CreateFile does have two versions because the file name can be either an ANSI string or a Unicode string. Win95 supports only the ANSI version.
The program uses one overlapped window, one popup window, and three child windows. We assign a "control ID" for each of the child windows, although we'll only refer to only one of them explicitly.
ID_mainedit equ 101 ID_popupedit equ 102 ID_popupbtn equ 103The child windows, or controls, have predefined classes. That leaves us with two windows to define classes for. The winmain module will register one window class. We'll need to register the other one in our initialization routine.
.data ; main window wc WNDCLASSEX <size WNDCLASSEX,CS_HREDRAW+CS_VREDRAW,WndProc,0,0, 0, \ 0,0,COLOR_WINDOW+1, 0,wndclsname,0> wndmain CREATEARGS <0,wndclsname,caption,WS_OVERLAPPEDWINDOW,\ 100,50,400,400, 0,0,0,0> wndedit CREATEARGS <0,editclsname,0,WS_CHILD+WS_HSCROLL+WS_VSCROLL+\ WS_VISIBLE+ES_AUTOHSCROLL+ES_AUTOVSCROLL+ES_MULTILINE,\ 0,0,0,0, 0,ID_mainedit,0,0> ; popup window wc_popup WNDCLASSEX <size WNDCLASSEX,0,PopUpWndProc,0,0, 0,\ 0,0,COLOR_3DFACE+1, 0,popupname,0> wndpopup CREATEARGS <0,popupname,0,WS_POPUP+WS_BORDER+WS_VISIBLE, \ 100,100,200,50, 0,0,0,0> wndfname CREATEARGS <0,editclsname,0,WS_CHILD+WS_VISIBLE+ES_AUTOHSCROLL,\ 0,0,200,20, 0,ID_popupedit,0,0> wndbtn CREATEARGS <0,btnclsname,btn_text,WS_CHILD+WS_VISIBLE,\ 0,25,40,21, 0,ID_popupbtn,0,0> hMain dd 0 hEdit dd 0 hFnameEdit dd 0 wndclsname db 'FileViewer',0 popupname db 'Popup',0 editclsname db 'edit',0 btnclsname db 'button',0 caption db 'File Viewer',0 btn_text db 'OK',0 public InitApp,EndApp extrn LoadCursor:near extrn GetModuleHandle:near extrn RegisterClassEx:near ; .code InitApp: mov esi,offset wc_popup mov edi,offset wc push large 0 call GetModuleHandle ; get program instance mov [esi].wcxInstance,eax push large IDC_ARROW push large 0 call LoadCursor mov [esi].wcxCursor,eax ; to wc_popup mov [edi].wcxCursor,eax ; to wc (main) push esi call RegisterClassEx mov esi,offset wndmain ret ; EndApp: xor eax,eax ; assume no errors retThe WM_CREATE handler is the only real difference between the main windows in this program and in our scratchpad editor. We save the main window handle, and create the popup window.
extrn CreateWindowEx:near finish_create: mov eax,[esp+4+0] ; grab hwnd before ESP changes mov [hMain],eax ; save for popup push esi push edi mov esi,offset wndedit mov [esi].cwargParent,eax ; make "wndmain" parent of "edit" mov eax,[wc].wcxInstance mov [esi].cwargInstance,eax ; set edit instance sub esp,48 ; allocate args mov edi,esp mov ecx,12 rep movsd call CreateWindowEx mov [hEdit],eax ; save edit window handle mov esi,offset wndpopup mov eax,[wc].wcxInstance mov [esi].cwargInstance,eax ; set popup instance sub esp,48 ; allocate args mov edi,esp mov ecx,12 rep movsd call CreateWindowEx pop edi pop esi xor eax,eax ; signal a successful CREATE ret 16The popup window is where most of our custom work appears. The button control, as a child of the popup, sends a WM_COMMAND to the popup when clicked. So we need to handle this extra message in our popup.
.code PopUpWndProc: mov eax,[esp+4+4] ; message ID cmp eax,WM_CREATE ; window created je finish_create_popup cmp eax,WM_COMMAND je do_command_popup cmp eax,WM_DESTROY ; about to start window destruction je start_destroy_popup jmp DefWindowProc ; delegate other message processingWhen we create the popup, we also create two controls and establish the popup as their parent. We save the edit control handle, so that we can retrieve the text that was entered there.
.code finish_create_popup: mov eax,[esp+4+0] ; grab hwnd before ESP changes push esi push edi mov esi,offset wndfname mov [esi].cwargParent,eax ; make "popup" parent of "edit" mov eax,[wc].wcxInstance mov [esi].cwargInstance,eax ; set edit instance sub esp,48 ; allocate args mov edi,esp mov ecx,12 rep movsd call CreateWindowEx mov [hFnameEdit],eax mov esi,offset wndbtn mov eax,[wndfname].cwargParent mov [esi].cwargParent,eax ; make "popup" parent of "button" mov eax,[wc].wcxInstance mov [esi].cwargInstance,eax ; set button instance sub esp,48 ; allocate args mov edi,esp mov ecx,12 rep movsd call CreateWindowEx pop edi pop esi xor eax,eax ; signal a successful CREATE ret 16Like the arguments for CreateWindowEx, we create an argument list data structure for CreateFile. We also set aside some storage for the file name and file data.
CREATEFILEARGS STRUC cfargFileName dd 0 cfargDesiredAccess dd 0 cfargShareMode dd 0 cfargSecurityAttr dd 0 cfargDistribution dd 0 cfargFlagsAndAttrs dd 0 cfargTemplateFile dd 0 CREATEFILEARGS ENDS .data ; "create" file arguments text_file CREATEFILEARGS <fname,GENERIC_READ,0,0,OPEN_EXISTING,\ FILE_ATTRIBUTE_NORMAL,0> bytes_transferred dd 0 fname db 256 dup(0) .data? fbuffer db 33000 dup(?) MAXBUF equ 32000 ; Win95 EDIT control is 16-bitThe only popup message we handle is the button click message. We do everything here except browse and terminate the program. Before exiting, we tell the popup window to destroy itself.
extrn ShowWindow:near,GetWindowText:near,DestroyWindow:near extrn CreateFile:near,ReadFile:near,CloseHandle:near extrn SetWindowText:near .code do_command_popup: mov eax,[esp+4+8] ; third arg is wParam cmp eax,(BN_CLICKED shl 16)+ID_popupbtn je button_click xor eax,eax ret 16 button_click: push esi push edi push large 255 push offset fname push [hFnameEdit] call GetWindowText ; get file name from edit window mov esi,offset text_file sub esp,28 ; allocate args mov edi,esp mov ecx,7 rep movsd call CreateFile cmp eax,INVALID_HANDLE_VALUE je no_file push eax ; push file handle for CloseHandle push large 0 ; no overlap structure push offset bytes_transferred push large MAXBUF push offset fbuffer push eax ; file handle call ReadFile call CloseHandle mov ecx,bytes_transferred mov fbuffer[ecx],0 ; terminate data push offset fbuffer push [hEdit] call SetWindowText no_file: ; restore esp (as well as edi and esi) pop edi pop esi push dword ptr [esp+4+0] ; hwnd of this window call DestroyWindow ; this window is no longer needed xor eax,eax ret 16We bring up the main window with this message, instead of in WM_COMMAND. This is in case the popup window was removed by another means (e.g., Alt-F4).
start_destroy_popup: push large SW_RESTORE push [hMain] call ShowWindow xor eax,eax ret 16